/*-------------------------------------------------------------------------
 *
 * pg_parameter_acl.c
 *	  支持pg_parameter_acl关系操作的常规例程
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/catalog/pg_parameter_acl.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/table.h"
#include "catalog/catalog.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_parameter_acl.h"
#include "utils/builtins.h"
#include "utils/pg_locale.h"
#include "utils/rel.h"
#include "utils/syscache.h"



/*
 * ParameterAclLookup - 给定一个配置参数名称， 
 * 查找相关配置参数 ACL 的 OID。 
 *
 * 如果 missing_ok 为 false，当找不到 ACL 条目时抛出错误。 如果 
 * 为 true，则只需返回 InvalidOid。
 */
Oid ParameterAclLookup(const char *fc_parameter, bool fc_missing_ok)
{
	Oid			fc_oid;
	char	   *fc_parname;

	/* 将名称转换为其在 pg_parameter_acl 中应有的形式... */
	fc_parname = convert_GUC_name_for_parameter_acl(fc_parameter);

	/* ... 然后查找它 */
	fc_oid = GetSysCacheOid1(PARAMETERACLNAME, Anum_pg_parameter_acl_oid,
						  PointerGetDatum(cstring_to_text(fc_parname)));

	if (!OidIsValid(fc_oid) && !fc_missing_ok)
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				 errmsg("parameter ACL \"%s\" does not exist", fc_parameter)));

	pfree(fc_parname);

	return fc_oid;
}

/*
 * ParameterAclCreate
 *
 * 向 pg_parameter_acl 添加新元组。
 *
 * parameter: 要为其创建条目的参数名称。
 * 调用者应已验证没有此条目。
 *
 * 返回新条目的 OID。
 */
Oid ParameterAclCreate(const char *fc_parameter)
{
	Oid			fc_parameterId;
	char	   *fc_parname;
	Relation	fc_rel;
	TupleDesc	fc_tupDesc;
	HeapTuple	fc_tuple;
	Datum		fc_values[Natts_pg_parameter_acl];
	bool		fc_nulls[Natts_pg_parameter_acl];

	/*
	 * 为了防止在 pg_parameter_acl 中填满无用条目，确保
	 * 名称有效。
	 */
	if (!check_GUC_name_for_parameter_acl(fc_parameter))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_NAME),
				 errmsg("invalid parameter name \"%s\"",
						fc_parameter)));

	/* 将名称转换为在 pg_parameter_acl 中应有的形式。 */
	fc_parname = convert_GUC_name_for_parameter_acl(fc_parameter);

	/*
	 * 创建并插入一个包含空 ACL 的新记录。
	 *
	 * 我们不会采取足够强的锁来防止并发插入，
	 * 而是依赖唯一索引。
	 */
	fc_rel = table_open(ParameterAclRelationId, RowExclusiveLock);
	fc_tupDesc = RelationGetDescr(fc_rel);
	MemSet(fc_values, 0, sizeof(fc_values));
	MemSet(fc_nulls, false, sizeof(fc_nulls));
	fc_parameterId = GetNewOidWithIndex(fc_rel,
									 ParameterAclOidIndexId,
									 Anum_pg_parameter_acl_oid);
	fc_values[Anum_pg_parameter_acl_oid - 1] = ObjectIdGetDatum(fc_parameterId);
	fc_values[Anum_pg_parameter_acl_parname - 1] =
		PointerGetDatum(cstring_to_text(fc_parname));
	fc_nulls[Anum_pg_parameter_acl_paracl - 1] = true;
	fc_tuple = heap_form_tuple(fc_tupDesc, fc_values, fc_nulls);
	CatalogTupleInsert(fc_rel, fc_tuple);

	/* 关闭 pg_parameter_acl，但保持锁直到提交。 */
	heap_freetuple(fc_tuple);
	table_close(fc_rel, NoLock);

	return fc_parameterId;
}
